package com.hmall.item.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.common.domain.PageDTO;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;

import com.hmall.item.domain.dto.ItemDTO;
import com.hmall.item.domain.dto.OrderDetailDTO;
import com.hmall.item.domain.po.Item;
import com.hmall.item.domain.query.ItemPageQuery;
import com.hmall.item.mapper.ItemMapper;
import com.hmall.item.service.IItemService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.naming.directory.SearchResult;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author itheima
 */
@Service
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements IItemService {

    @Autowired
    private RestHighLevelClient client;

    @Override
    public void deductStock(List<OrderDetailDTO> items) {
        String sqlStatement = "com.hmall.item.mapper.ItemMapper.updateStock";
        boolean r = false;
        try {
            r = executeBatch(items, (sqlSession, entity) -> sqlSession.update(sqlStatement, entity));
        } catch (Exception e) {
            log.error("更新库存异常", e);

//            return;

            throw new BizIllegalException("库存不足！");
        }
        if (!r) {
            throw new BizIllegalException("库存不足！");
        }
    }

    @Override
    public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
        return BeanUtils.copyList(listByIds(ids), ItemDTO.class);
    }

    //TODO : 将搜索的数据库升级为搜索ES
    @Override
    public PageDTO<ItemDTO> search(ItemPageQuery pageQuery) {
        try {
            //1．创建搜索对象
            SearchRequest searchRequest = new SearchRequest("items");

            //2.封装搜索条件：搜索框、分类、品牌、价格


            //bool包裹所有查询条件
            BoolQueryBuilder booledQuery = QueryBuilders.boolQuery();

            //2.1 搜索框 如果搜索框有数据进行模糊查询，如果没有进行match——all查询
            if (StrUtil.isNotBlank(pageQuery.getKey())) {
                booledQuery.must(QueryBuilders.matchQuery("name", pageQuery.getKey()));
            }

            //2.2分类、品牌、价格
            if (StrUtil.isNotBlank(pageQuery.getCategory())) {
                booledQuery.must(QueryBuilders.termQuery("category", pageQuery.getCategory()));
            }
            if (StrUtil.isNotBlank(pageQuery.getBrand())) {
                booledQuery.must(QueryBuilders.termQuery("brand", pageQuery.getBrand()));
            }
            if (pageQuery.getMinPrice() != null && pageQuery.getMaxPrice() != null) {
                booledQuery.must(QueryBuilders.rangeQuery("price").from(pageQuery.getMinPrice()).to(pageQuery.getMaxPrice()));
            }

            //2-4 使用算分函数 提供广告商品的排名

            FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(booledQuery,
                    new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                            new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                    QueryBuilders.termQuery("isAD", true),
                                    ScoreFunctionBuilders.weightFactorFunction(50))
                    }
            );


            searchRequest.source().query(functionScoreQuery);

            //3．指定分页参数
            searchRequest.source()
                    .from((pageQuery.getPageNo() - 1) * pageQuery.getPageSize())
                    .size(pageQuery.getPageSize());


            //4．指定排序方式和字段
            if (StrUtil.isNotBlank(pageQuery.getSortBy())) {
                searchRequest.source().sort(pageQuery.getSortBy(), pageQuery.getIsAsc() ? SortOrder.ASC : SortOrder.DESC);
            }

            //5.高亮设置
            searchRequest.source().highlighter(
                    SearchSourceBuilder.highlight()
                            .field("name")
                            .requireFieldMatch(false)
            );

            //6．发送请求，执行搜索
            searchRequest.source().query(booledQuery);

            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);


            //7.解析结果：：封装dto/解析高亮

            //定义一个list接受dto
            List<ItemDTO> list = new ArrayList<>();

            long total = response.getHits().getTotalHits().value;
            SearchHit[] hits = response.getHits().getHits();
            for (SearchHit hit : hits) {
                ItemDTO itemDTO = JSONUtil.toBean(hit.getSourceAsString(), ItemDTO.class);

                //解析高亮
                if (hit.getHighlightFields().containsKey("name")) {
                    itemDTO.setName(hit.getHighlightFields().get("name").getFragments()[0].toString());
                }

                //添加到集合中
                list.add(itemDTO);
            }
            //计算总页数
            long pages = total % pageQuery.getPageSize() == 0 ? total / pageQuery.getPageSize() : total / pageQuery.getPageSize() + 1;

            //8返回结果
            return new PageDTO<>(total, pages, list);


        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


}
